gRPCアプリをAWS ELBで負荷分散してみた
ども、大瀧です。
先月GAを迎えたGoogle製RPCフレームワークgRPCをちまちま触っています。
gRPCクライアントからgRPCサーバーへの負荷分散は、GitHubでクライアントサイドの例が紹介されていますが、今回はAWSのELB(Elastic Load Balancer)を用いたL4ロードバランサによる負荷分散を試してみた様子をレポートします。
ELBのgRPCサポート状況
gRPCは、HTTP/2上にProtocol Buffers形式でデータの送受を行います。HTTP/2サポートと言うと、AWSでは最近追加されたApplication Load Balancer(ALB)を連想するところですが、ALBがHTTP/2に対応しているのはリスナーであり、ターゲット(バックエンド)へのHTTP/2転送には対応していません。また、こちらのブログ記事に倣いALBのバックエンドにnghttpxを置いてHTTP/1.1からHTTP/2へのリバースプロキシとして組み合わせてみましたが、ALBがTEヘッダを転送しないようでうまく接続できませんでした。以下のGoogleグループでも話題になっています。
Classic Load Balancerは、HTTP/2には非対応ですがL4(TCP)ロードバランサーとして設定することでgRPCのトラフィックを転送することができます。というわけで今回はClassic Load BalancerのTCPモードで試してみます。
検証環境
- EC2 : Amazon Linux AMI 2016.03.3 (HVM), SSD Volume Type - ami-374db956
サーバー側は、gRPCのGo版サンプルのサーバーアプリケーション("Hello world"というメッセージを返す)を以下のユーザーデータでDockerコンテナとして実行しました。
#!/bin/bash yum install -y docker service docker start chkconfig docker on docker run -d \ -p 50051:50051 \ grpc/go:latest \ go run /go/src/google.golang.org/grpc/examples/helloworld/greeter_server/main.go
ポート番号50051番でListenするので、ELBからアクセスできるようにセキュリティグループを調整しましょう。
続いてClassic Load Balancerを作成します。今回はTCP:50051
からTCP:50051
に転送するように設定しました。
ヘルスチェックも同じTCP:50051
にしておきます。
これでOKです。手元からはNode.js版サンプルのクライアントの接続先を以下のように変更しました。
var client = new hello_proto.Greeter('XXXXXXXX.ap-northeast-1.elb.amazonaws.com:50051', grpc.credentials.createInsecure());
では、実行してみます。
$ node greeter_client.js Greeting: Hello world $
正常に接続することが出来ました!
まとめ
ELBをgRPCサーバーのロードバランサとして利用するために、Classic Load BalancerのTCPモードをご紹介しました。今回は単発のリクエスト/レスポンスの例でしたが用途によってはLong Pollingなど長時間接続する場合もあると思うので、Classic Load Balancerのアイドルタイムアウトの設定を調整すると良いと思います。
また、今回はTCPモードなので取れませんが、プロキシなどでアクセスログを取得しデバッグするときはgRPCのGitHubのHTTP/2仕様が有用だと思います。
余談
SSL Terminationもできるかな?とACMの証明書をClassic Load BalancerにセットしてリスナをSSL(セキュアTCP)
にしてみましたが、Missing selected ALPN property
というエラーになったので、Classic Load BalancerがTLSのALPN拡張に対応してなさそうでした。